Table of Contents
List of Tables
List of Examples
Table of Contents
This document outlines the system design of GRINS for collaborators interested in contributing to GRINS development. We begin with an overview of the design and enumerate various components, followed by a detailed description of each component and its interaction protocol with other components. Finally, we describe the API and provide pointers to sample code for writing new services and applications on GRINS. The best way we suggest for new collaborators to ramp up on GRINS is to first use it, then read this document once to get a broad sense of the architecture, and then re-read it while browsing the API docs at the same time.
GRINS is designed in a service oriented manner. Thus, we have an Audio Service which is responsible for playing out audio, an Archiver Service which records any mic inputs, Index and Library Services which take care of indexing and search, etc. The GRINS application contacts these services for various tasks based on user interactions. In addition, these services can be distributed across different machines, and they talk to each other over the LAN through an IPC (Inter Process Communication) protocol we have built ourselves. Such a flexible multi-machine setup is important to ensure that GRINS can be plugged into just about any kind of a radio station setup. We have invested considerable effort in building a robust platform -- services may crash, or networks may get disconnected, or machines may lose power -- but GRINS maintains appropriate state information so that recovery is automatic and as non-disruptive as possible.
GRINS currently provides the following services, also shown in the sample deployment figure below.

Audio Service: Uses GStreamer to play out audio from a file through a sound card. Two instances of the Audio Service are shown in the figure: a Playout Service which plays out audio into the soundcard that is connected to the FM transmitter, and a Preview Service which plays out audio into the headphones of the radio station operator.
Archiver Service: Uses GStreamer to archive audio coming in through a sound card into a file. This is used to archive any live speech made by the radio station operator.
Mic Service: Redirects mic input from a soundcard into the output of the same or a different soundcard on the same machine. This is used when a mic is directly attached to a GRINS machine, as in the figure, and so the mic input has to be sent out on broadcast through a soundcard.
Monitor Service: Similar to the Mic service, this redirects audio from the input of a soundcard into the output. This is used by the radio station operator to listen to the live transmission going out on air. The difference from the Mic Service is that the Monitor Service can be preempted by the Preview Service if the radio station operator wants to listen to some audio programs.
Library Service: Stores program metadata, playout history, and other information in a mysql database.
Index Service: Uses Lucene to index the metadata for search queries.
UI Service: The user-interface runs as a service too. The application architecture of how the UI communicates with different services is explained in the next section.
All communication across services happens through messages, and an IPC server acts as the single point of coordination for routing messages between these services. As should be evident from the discussion so far, GRINS can support different services running off different machines in different configurations. Of course, this is subject to certain constraints, for example, that the Archiver and Mic Service have to run on the same machine since they share the same sound card, and the Monitor and Preview Service have to run together because they share the same headphones. We are working to express these constraints in a formal manner and to use Prolog for infering logically consistent configurations, because the setup is going to become a lot more complicated once we build the telephony and other services on GRINS. We next explain the control flow across different services and the GRINS application.
The figure below shows the protocol stack used for communication between the GRINS application and services. All communication is intermediated by an IPC Server which runs on a machine especially designated as the RS Controller machine. The RS Controller also runs a resource manager which keeps track of assigning audio and other hardware devices to different services. Each service communicates with the IPC Server through an IPC Server Stub, and the server has corresponding IPC Node Stubs for each externally running service. Note that these various stacks can run off a single machine as well -- the separation as shown here is only a logical separation between different entities.
Shown on the left is the GRINS application, which runs the UI service. The application is designed as a collection of widgets. Thus, we have a Playlist Widget which can be used to manage playlists, a Library Widget to search the library based on the metadata of uploaded programs, a Metadata Widget to edit the metadata of individual programs, etc. Each widget does not directly interact with a service, but interacts with a service stub in the application, which we call a provider for the service. A single widget may use multiple providers. For example, the Playlist Widget uses the Playout and Preview Providers to interact with the Audio Service, the Archiver Provider to interact with the Archiver Service, etc. Each provider uses the UI Service to communicate with its corresponding service. In this way, widgets use an API to interact with different providers, and providers use messages to communicate with services. Note that the various Widget classes in the code base only implement the UI functionality; each Widget has a corresponding Controller class which actually interacts with the different providers, following the MVC paradigm.

Table 1.1. Widget -- Provider -- Service relationships
| Widget | Provider | Service | Comments |
|---|---|---|---|
| Playlist Widget | Playout Provider | Audio Service | To playout the currently live audio program |
| Preview Provider | Audio Service | To preview a program when the preview button is pressed on some item | |
| Archiver Provider | Archiver Service | To archive live speech when the mic is active | |
| Metadata Provider | Index Service | To open up the Metadata Widget when the info button is pressed on some item | |
| Monitor Provider | Monitor Service | To hear the live transmission which is being sent out to the transmitter | |
| Mic Provider | Mic Service | To redirect live speech on a mic to playout for the transmitter | |
| Library Widget | Library Provider | Library Service | To search the library when the search button is pressed or a filter is activated |
| Preview Provider | Audio Service | To preview a program when the preview button is pressed on some item | |
| Metadata Provider | Index Service | To open up the Metadata Widget when the info button is pressed on some item | |
| Metadata Widget | Metadata Provider | Index Service | To update the index when the metadata of an item is edited |
| Hotkeys Widget | Playout Provider | Audio Service | To playout the currently selected hotkey |
| Upload Widget | Upload Provider | Upload servlet | To upload programs into the library |
| Diagnostics Widget | Playout Provider | Audio Service | To test playout |
| Mic Provider | Mic Service | To test the mic | |
| Preview Provider | Audio Service | To test preview | |
| Archiver Provider | Archiver Service | To test archiving | |
| Library Provider | Library Service | To check the library | |
| Upload Provider | Upload servlet | To check upload | |
| Monitor Provider | Monitor Service | To test the monitor |
Cache Provider: In addition to these providers, it is also worth mentioning the Cache Provider. All access to the database for querying metadata is done through this provider, which maintains a single instance of each metadata object in the memory. Thus, if the same item appears in a library search, or in a playlist, or its metadata is being edited, only a single instance is maintained in the memory. Further, any changes to this object are automatically reflected in all widgets displaying information about the object. This not only improves the memory usage in the GRINS application, but also helps synchronize changes across different widgets which refer to the same object. In certain cases where caching does not make sense, a provision is available to directly interact with the database as well.
We next explain the role of the Resource Manager, and describe some control messages exchanged between services and the Resource Manager.
We consider all soundcards as resources, and services make requests to the Resource Manager to acquire these resources. Requests are typically made when some operation initiated by the application needs a resource, such as playout of a program requires the Audio Service to acquire the output port of the playout soundcard. Persistent requests can also be made, in which case resources are automatically assigned to the requesting service whenever the resource becomes free. The Resource Manager keeps track of all resource allocations.
The second job of the Resource Manager is to maintain service interests: providers on the GRINS application express interests to the Resource Manager about services they want to interact with. Whenever a service becomes active, all interested providers are notified about the event. The providers in turn notify various widgets using them, and widgets accordingly enable or disable the functionality corresponding to the concerned provider. Services can also express interests in other services, in which case the same protocol is followed: whenever a service becomes active, notifications are sent to all interested services.
The Resource Manager also keeps careful track of the health of different services. All services are expected to respond within a 500ms timeout to heartbeat messages sent by the Resource Manager. If a heartbeat fails, error notifications are sent out other services. If a service itself sends an error message, these messages are also relayed to other services. A problem that often arises upon noticing an error with some service is to determine whether the service went down, or the network went down. This is important because if a network failure is short-lived then the service or any other dependencies need not be reset; however, if the service itself goes down and restarts, then state needs to be reset in all widgets and providers associated with the service. For example, if the Audio Service gets temporarily disconnected for some reason while it is playing out a program, but the network comes back up very soon, then the service and the playlist should not be reset. The Resource Manager therefore maintains a registration-id for each service instance. Whenever a service connects, it sends the last registration-id, and if this does not match the id held by the Resource Manager then the service is instructed to reset itself. The Resource Manager can also directly ping a service machine to check the network; if the network is up but the service is not responding, it means that the service crashed and will restart itself soon.
Table of Contents
We next describe various steps involved with playing out audio from a file. The interaction shown in the figure below includes the playlist and other widgets in the GRINS application, the playout provider, and the audio service. We start with describing the service, and then move up the stack.
The Audio Service has been designed to run in either the playout role or the preview role, with different resources (aka. soundcards) assigned to different roles. An audio session is created whenever a PLAY command is received by the service, and can be followed by PAUSE or STOP commands. Commands to change volume levels are also interpreted by the Audio Service. All commands are sent as messages through IPC by the Playout and Preview Providers.
The providers expose a simple API to widgets, and hide all complexity of sending commands as messages to the service, and receiving responses from the service. The API exposed to the widgets consists of simple calls such as play(file-id), pause(file-id), stop(file-id), volumeUp(n), volumeDn(n), etc. In addition, generic calls to indicate service failure or reset are also conveyed to the widget so that it can accordingly reset itself.
The widgets themselves are written in a MVC manner: the widget classes render the user interface, and corresponding controller classes take action based on user inputs and accordingly direct the Playout and Preview Controllers. The Playout Provider is invoked only by the Playlist Widget for playing out audio. However, the Preview Provider is invoked by all widgets that allow the user to preview audio programs, namely, the Playlist, Library, Upload, and Simulation Widgets.
The Audio Service internally uses GStreamer for playing out audio. GStreamer is an opensource audio and video library with support for a number of codecs, audio analysis algorithms, streaming, archiving, etc. The most interesting concept that forms the basis of GStreamer is the notion of elements and pipes: Codecs, analysis tools, etc are all elements in GStreamer, and can be strung together in a pipe. The output of one element can feed into the input of another element, and pipes can also be split or merged together. This is of significant value to us because often multiple audio streams will have to be mixed together, for example, if a live Mic input has to be mixed with a hotkey playout, or two files have to be simultaneously played out. Most soundcards support mixing in hardware, but it is a good failsafe to have mixing support in the application as well.
The Audio Service is designed to work in an asynchronous message passing manner. All commands and responses are encapsulated in IPC messages, as shown in the interaction diagram below for a PLAY command. Although our IPC mechanism supports synchronous request-response as well, but we chose the asynchronous route to avoid any waiting periods in the user-interface.

Similar to audio playout, archiving involves the Playlist Widget, the Archiver Provider, and the Archiver Service. The service responds to commands such as START archiving and STOP archiving, and replies back with asynchronous callbacks on the success or failure status. GStreamer is used for archiving live audio into a WAV file. Since WAV files can become quite large, an encoder runs in the background and encodes new recordings in MP3. Since encoding is computationally intensive, it is done only during idle periods of the CPU.
Interactions with the library follow a slightly different design for some tasks. There are three kinds of interactions:
Search: The standard method is used here: the Library Widget makes API calls on the Library Provider, which invokes the Index Service. Searhc results are then returned in a synchronous manner.
Metadata query: This is done through API calls to the Cache Provider, which directly queries the database and returns the result. Practically all widgets invoke the Cache Provider to get details on various audio programs, or update playout logs, or manage playlists.
Metadata editing: This involves two steps. First, any edits are passed to the database by directly connecting to it. Second, once the database has been updated, the Index Service is invoked through the Metadata Provider to update the Lucene index with the new metadata information.
Mysql is used as the database backend, and we have designed our own object-relational mapper to interact with the database. The OR mapper maintains a Java class file for every table in the database, and uses Java reflection to map fields in the class with columns in its corresponding table. Thus, if a widget or the some provider or service wants to directly interact with the database, they do not have make explicit JDBC calls each time; the JDBC calls are masked by a simple OR API. This API consists of calls such as select(object), which parses the object using Java reflection and generates a SQL query based on fields that have been initialized in the object. Similarly, insert(object), update(old object, new object), and other variants of select calls are provided in the API.
Lucene is used for indexing, and flattens out the metadata to index fields such as the program title, description, artists, categories, language, trivia, etc. If the index gets damaged for some reason, it can even be reinitialized from scratch. The index can then be searched using keywords, or specific fields can also be queried separately.
This definitely warrants some explanation. As shown in the screenshot of the Library Widget below, GRINS allows multiple facets to be assigned to each item. Facets are like categories, except that different facets are orthogonal to each other. For example, a facet assignment to an item of some artist is orthogonal to the assignment of a health related facet, which is orthogonal to the length facet, the demography facet, etc. These facets are expressed through filters, and while searching, different filters can be applied to the search criteria and get ANDed with each other. Internally, some filters translate to database queries, while others translate to text search on the Lucene index: in all cases, the search query makes its way to the Index Service, which collects matching programs and returns the result to the application.

Audio upload is different from other application -- server interactions because the service runs as a servlet. In addition, since GRINS could be installed over multiple machines, uploaded files have to be replicated on all machines from where a playout is possible. We therefore introduced the concept of a file store: File stores can be either producers or consumers. The Archiver Service is an example of a producer file store because it introduces new files into the system. Similarly, an upload servlet running with the Library Service is another producer file store because all files are first uploaded to the library. GRINS then takes take of replicating new files into other consumer file stores, which currently only include the Playout and Preview Services. Note that if different file stores are collocated on the same machine, then only one copy of the file is maintained on that machine.
The upload interaction therefore works out as follows. When a file is uploaded from the GRINS application, if a file-store is present locally then the file is simply copied into that file store. In addition, the file is also uploaded to the servlet running with the Library Service. The library then takes responsibility of replicating the file on other consumer file stores. Statistics are maintained in the database of which file stores have been updated with the file. Whenever a new file store is updated, cache invalidation messages are also sent to the application to accordingly enable or disable functionality corresponding to the availability of that file. For example, if a file is not present on the preview file store, then the preview button is disabled until the file gets replicated on that file store.
The Diagnostics Widget interacts with almost all providers to test the reachability of different services, and the correctness of their working. The Playout and Preview Services are evaluated by generating a sine wave and analysing it at the other end to check the audio quality. Similarly, the Archiver Service is checked by examining the volume level of audio coming in through the mic. In addition, uploading is checked by uploading a dummy file, the index and database are checked by generating dummy queries, and all file stores are checked for their remaining amount of diskspace. The role of the diagnostics component is to check all network and audio connections, and to guide the radio station operator to fix cable faults locally. This is envisioned to reduce the downtime of radio stations if misconfigurations happen or minor faults arise in the system.
Table of Contents
Hopefully by now you would have acquired a broad idea of the GRINS architecture. The next step would be to dive into the configuration file and map all the concepts discussed above to tangible objects. We will then guide you through setting up a development environment, then describe some key classes and packages, and finally give details on how to write your own services and widgets on GRINS.
The automation.conf configuration file is organized into different sections. Following are some of the main sections that you should be able to relate with the description given above.
Example 3.1. automation.conf
#machine details: [IP address, ID]
[machines]
RSCONTROLLER_MACHINE, 127.0.0.1
RSAPP_MACHINE, 127.0.0.1
LIB_MACHINE, 127.0.0.1
#provider details: [providerName, providerClass]
[providers]
PLAYOUT_PROVIDER, org.gramvaani.radio.app.providers.PlayoutProvider
PREVIEW_PROVIDER, org.gramvaani.radio.app.providers.PreviewProvider
ARCHIVER_PROVIDER, org.gramvaani.radio.app.providers.ArchiverProvider
LIBRARY_PROVIDER, org.gramvaani.radio.app.providers.LibraryProvider
MEDIALIB_UPLOAD_PROVIDER, org.gramvaani.radio.app.providers.MediaLibUploadProvider
METADATA_PROVIDER, org.gramvaani.radio.app.providers.MetadataProvider
CACHE_PROVIDER, org.gramvaani.radio.app.providers.CacheProvider
#services details: [serviceName, serviceClass, machineID, serviceInstanceName]
[services]
AUDIO_SERVICE, org.gramvaani.radio.rscontroller.services.AudioService, RSCONTROLLER_MACHINE, AUDIO_SERVICE_PLAYOUT
AUDIO_SERVICE, org.gramvaani.radio.rscontroller.services.AudioService, RSCONTROLLER_MACHINE, AUDIO_SERVICE_PREVIEW
ARCHIVER_SERVICE, org.gramvaani.radio.rscontroller.services.ArchiverService, RSCONTROLLER_MACHINE, ARCHIVER_SERVICE_COMMON
UI_SERVICE, org.gramvaani.radio.rscontroller.services.UIService, RSAPP_MACHINE, UI_SERVICE
LIB_SERVICE, org.gramvaani.radio.rscontroller.services.LibService, LIB_MACHINE, LIB_SERVICE
INDEX_SERVICE, org.gramvaani.radio.rscontroller.services.IndexService, LIB_MACHINE, INDEX_SERVICE
#services used by providers: [providerName, serviceInstanceName, role]
[providerservices]
PLAYOUT_PROVIDER, AUDIO_SERVICE_PLAYOUT, PLAYOUT
PREVIEW_PROVIDER, AUDIO_SERVICE_PREVIEW, PREVIEW
ARCHIVER_PROVIDER, ARCHIVER_SERVICE_COMMON, mic
#resource details: [resourceType, resourceName, machineID]
[resources]
SOUNDCARD_OUT, soundcardalsa1_out, RSCONTROLLER_MACHINE
SOUNDCARD_OUT, soundcardalsa2_out, RSCONTROLLER_MACHINE
SOUNDCARD_OUT, soundcardwin1_out, RSCONTROLLER_MACHINE
SOUNDCARD_OUT, soundcardwin2_out, RSCONTROLLER_MACHINE
SOUNDCARD_IN, soundcardalsa1_in, RSCONTROLLER_MACHINE
SOUNDCARD_IN, soundcardalsa2_in, RSCONTROLLER_MACHINE
SOUNDCARD_IN, soundcardwin1_in, RSCONTROLLER_MACHINE
SOUNDCARD_IN, soundcardwin2_in, RSCONTROLLER_MACHINE
#resources used by services: [serviceName, resourceName, resourceRole]
[serviceresources]
AUDIO_SERVICE_PLAYOUT, soundcardalsa1_out, PLAYOUT
AUDIO_SERVICE_PREVIEW, soundcardalsa2_out, PREVIEW
ARCHIVER_SERVICE_COMMON, soundcardalsa1_in, mic
#configuration of resource: [resourceName, resourceMixer, resourceDeviceName]
[resourceconfig]
soundcardalsa1_out, ALSA, hw0,0
soundcardalsa1_in, ALSA, hw0,1
soundcardwin2_out, ALSA, hw1,0
soundcardwin2_in, ALSA, hw1,1
The [machines] section specifies machine names and IP addresses. Note that these need not be physically distinct machines, but each machine-id represents a distinct virtual machine that will run on the specified IP address. Thus, here we have specified three virtual machines, for the RS Controller, UI machine, and the library machine respectively.
The [providers] section enumerates all active providers and specifies the classes implementing them. The [machines] section specifies machine names and IP addresses. Note that these need not be physically distinct machines, but each machine-id represents a distinct virtual machine that will run on the specified IP address. [services] defines the service name, the implementing class, the machine on which the service will run, and the instance name. Note that some services like the Audio Service can have multiple instances. The [providerservices] section specifies the service instances that different providers communicate for different roles. These entries are made only for those providers that may have a choice of service instances based on different roles.
Finally, the [resources] section lists virtual names for different resources. These are used by the resource manager to detect conflicts in resource requests. Various resources are listed based on whether they represent the input or output of a soundcard, and the machine on which they reside. [serviceresources] specifies the resources used by different service instances for different roles. The [resourceconfig] section then maps various virtual resource names to the physical device they represent.
The ideal development environment to have is to run everything off your local machine. You can set up GRINS on your laptop and carry your environment with you whereever you go! GRINS source code can be downloaded from the links below. The package marked Common contains the actual code. GRINS depends on several other packages for it to be compiled and run. A list of these dependencies is provided in the README present in the Common package. To make things slightly easier we have created packages containing most of the dependencies. One has been created for Ubuntu and another one for Windows environment. These packages are present below. The only dependency not included in the packages below is that of Java SDK. You can go through the dependencies specified in the README and install them one by one.
| Common (7 MB) containing GRINS and its documentation, installation scripts | Download |
| Linux (71 MB) containing mysql, gstreamer, java, and tomcat dependencies | Download |
| Windows (157 MB) containing mysql, gstreamer, java, and tomcat dependencies | Download |
Once all the dependencies have been installed, cd into the gramvaani-automation directory, and run make. Make sure that the right Java compilation binaries are included in the PATH. If the compilation goes well, you should be able to launch GRINS by running two commands in different windows:
This starts the RS Controller with all services running in the same virtual machine.
This starts the GRINS application.
The source code is in the src directory and the world is in front of you!
Note that you can also run some services in their own virtual machine instead of running all services in the RS Controller. This could be useful especially for debugging where you may want certain service logs to be isolated from the rest of the logs the system might be generating. Taking the example of the automation.conf example given above, the library and index services have been specified to run in the LIB_MACHINE. The virtual machine for this can be started through the following command:
This starts the RSServiceInstantiator (explained later) to run the Library and Index Services.
We next describe the package structure and some important classes that you are likely to encounter.
This contains our IPC implementation. Various services implement the IPCNode interface, and use the IPCServerStub to communicate with the IPC Server. The server itself is implemented in IPCServerImpl, and uses IPCNodeStub objects to communicate with various services implementing IPCNode.
The IPCMessage class is the parent class for all asynchronous IPC messages. Synchronous messages extend the IPCSyncMessage and IPCSyncResponseMessage classes.
This contains various utility methods for string parsing, file copy, GUID generation, icon sizing, etc.
This implements heartbeat message passing to continuously monitor the status of services running on different machines.
The main classes here are the StationConfiguration and StationNetwork classes. StationConfiguration reads the configuration file on startup, and makes its values available to other entities which need this information. StationNetwork encapsulates the configuration of the radio station by exposing an API to find out the number of machines in the setup, machine details, which service instances are running on which machines, which file stores are in use, etc.
This contains a single TimeKeeper class which is meant to be the single point in the setup that provides the current time. The time is taken to be the time on the UI machine, and any service requiring the current time queries the UI Service for this value.
This contains a single RSApp class which starts the GRINS application UI. This is invoked through the following command:
perl scripts/run.pl app
This contains various widgets and controller classes. The base UI classes are the ControlPanel and ControlPanelJFrame classes. The UI is divided into a bottom panel which shows icons for different widgets (BottomMenuPanel), the top panel which displays error messages (TopMenuPanel), the active scroll panel on the right which shows the minimized display for active widgets (ActiveScrollPanel), and the workspace panel (WorkSpacePanel) which encapsulates the actual working space allocated to widgets. To begin understanding widget code, it is best to start with one of the simplest widgets, such as the LogViewWidget.
This contains the various provider classes. Again, one of the simplest ways to begin understanding provider code is to start with a simple provider, such as the ArchiverProvider. Note that almost all providers also have callback interfaces: this is to raise callbacks such as error events or convey return values to different widgets using the provider. Widgets are therefore expected to register themselves with providers before they start using the provider API, and implement the respective callback interfaces of providers they use. All providers extend the RSProviderBase class which interfaces communication between providers and the UI Service.
As the name suggests, RSController implements the RS Controller. It contains single instances of IPCServiceImpl and the resource manager, and its virtual machine also encapsulates various services designated to run on the RSCONTROLLER_MACHINE. The RSServiceInstantiator is similar to the RS Controller because it runs on a separate machine and encapsulates services designated to run on that machine. However, it does not run an IPC Server or resource manager.
The RSController and RSServiceInstantiator are executed as follows:
perl scripts/run.pl rsc
perl scripts/run.pl rsi "-m service-instance-name"
Various services are implemented here. Some of the simpler services to get acquainted with are the MicService and ArchiverService. All services implement the IPCNode and IPCNodeCallback interfaces for communicating with the IPC Server, the LinkMonitorClientListener interface for listening to heartbeat messages sent by the IPC Server, and the DiagnosticsUtilitiesCallback interface which is explained later.
This contains various asynchronous and synchronous messages used for communicating with services. Note that all messages are currently instantiated in the MessageFactory. This will later be moved out into the configuration file.
This contais the GStreamer wrapper classes which interact with GStreamer through its Java bindings, and expose a simple API for services to use.
This contains a single MediaLibUploadServlet which runs wihin Tomcat to upload files into various file stores.
This contains classes that implement the heart of the database and indexing operations. MediaLib maintains a singleton instance of itself with one connection to the database server, and implements the object-relational mapper to expose a simple API for database interactions with other GRINS components. IndexLib implements corresponding functionality for interacting with Lucene, and is used by the Index Service to initiate re-indexing upon metadata updates, or to respond to metadata search queries.
An important class is the Metadata class. This is the parent class for all objects that map to tables in the database. For example, the RadioProgramMetadata class maps to the RadioProgramMetadata table in the database, and contains fields corresponding to different columns in the database. Some columns can also be declared as foreign keys into other tables, in which case MediaLib can even recursively generate select queries.
This contains various classes to proactively check network connections with other machines, such as the RS Controller machine or the database machine. We try to disambiguate between cases where the network went down, or some service or external component such as a database server went down. Automatic remote restarts are initiated accordingly. High temperature alerts are also raised if the CPU temperatures start running too high, and the system shuts itself down.
Some important functionalities going to come out soon are the Telephony Service and the SMS Service. The Telephony Service will enable people to call into the radio station and interact with the operator, who can optionally put them live on air. People will also be able record comments such as local advertisements, informational questions, announcements, etc, which can be previewed by the radio station operator and played out. Similarly, the SMS Service will make it possible for people to send SMS messages to the radio station operator about various programs, or even conduct an SMS poll.
The combination of telephony and radio will enable a whole new class of multiplanar applications that do not exist today. Applications such as polling, rural marketplaces, classifieds, discussions, etc would all be possible. Plus, many more applications that we have not even thought of ourselves. So, pitch in and let's change the world!