Find the answer to your Linux question:
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 11
Hi, I am writing an application on a Beagleboard (running Ubuntu) which reads sound samples from a microphone (using ALSA APIs), compresses them and writes it to the serial port ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    May 2009
    Location
    Rolla, MO
    Posts
    5

    Duplex communication thro serial port


    Hi,

    I am writing an application on a Beagleboard (running Ubuntu) which reads sound samples from a microphone (using ALSA APIs), compresses them and writes it to the serial port to a radio (which broadcasts it). For duplex communication, i need to receive the data from the radio (by reading from the serial port), uncompress it and send it to the speaker (again through ALSA APIs). The problem here is that the whole operation is performed in a loop. I am writing byte by byte into the port and sending it to the radio. However the radio writes 80 bytes as and when it receives a packet and there is no synchronization between the two devices. Effectively i am unable to read any data from the serial port. Can anyone suggest a better method of implementation ?

    Thanks in advance,
    Priya.

  2. #2
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,393
    You can either use two processes, or two threads. One that reads the data from the microphone and writes to the serial port, and another that reads the data from the serial port and writes to the audio system. As you have seen, doing it as you are now has inherent, and often insurmountable problems with data syncronization. I used to do the same thing with terminal emulators that had to read and write to a serial port at the same time. The principle is the same, except instead of reading the keyboard and writing to the display, you are reading and writing to the sound sub-system (ALSA API's). The rest of the application structure is much the same.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  3. #3
    Linux Newbie tetsujin's Avatar
    Join Date
    Oct 2008
    Posts
    117
    If I'm understanding correctly, the basic problem is this:

    You're reading from and writing to various sources (read/write on serial port, read from audio input, write to audio output...) Each of these sources has a buffer that determines how much data can be fed into or taken out of it before it starts blocking further requests... Thus on an attempt to write to the serial port, the execution of that write may be blocked until enough bytes from the serial port buffer have been written out to the wire to give you sufficient buffer space for the new data - thus delaying your attempt to read incoming data from the serial port, etc...

    A single-threaded approach to solving this, if that is what's going on here, would be to use non-blocking I/O and select() to see which sources of incoming data have data ready for you to read. When you use a non-blocking I/O you need to be prepared for an attempt to read() or write() to process less data than you asked it to...

  4. #4
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,393
    Quote Originally Posted by tetsujin View Post
    If I'm understanding correctly, the basic problem is this:

    You're reading from and writing to various sources (read/write on serial port, read from audio input, write to audio output...) Each of these sources has a buffer that determines how much data can be fed into or taken out of it before it starts blocking further requests... Thus on an attempt to write to the serial port, the execution of that write may be blocked until enough bytes from the serial port buffer have been written out to the wire to give you sufficient buffer space for the new data - thus delaying your attempt to read incoming data from the serial port, etc...

    A single-threaded approach to solving this, if that is what's going on here, would be to use non-blocking I/O and select() to see which sources of incoming data have data ready for you to read. When you use a non-blocking I/O you need to be prepared for an attempt to read() or write() to process less data than you asked it to...
    Your suggestion is a common approach for handling asynchronous I/O, but still has indeterminate latency in processing the incoming or outgoing data. Since the I/O is truly asynchronous, you will still benefit by using separate threads or processes to handle input and output. On a multi-core system, it will make significant improvements in handling high-speed I/O, and on a single core system it will still be an improvement since context switching is a lower-overhead operation in all likelihood, and usually quite determinate in timing matters. Also, if not losing incoming data is more important than handling outgoing data, you can also increase the priority of the outgoing thread, or vice-versa if necessary.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  5. #5
    Just Joined!
    Join Date
    May 2009
    Location
    Rolla, MO
    Posts
    5
    Thanks everyone. I am now using two separate threads - one for microphone and serial write and the other for serial read and speaker write. I am facing another problem here. The speaker expects samples at 8kHz. So i am using a non blocking read to get 80 bytes from the serial port and passing it as soon as possible to the speaker. Here again I have synchronization issues because of the non blocking read. I am not able to get 80 bytes. A blocking read may not provide data at the required speed. Please suggest what can be done.

    Thanks,
    Priya.

  6. #6
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,393
    A non-blocking read will only read as much data as is available. Try adding another thread that just reads the data, and passes it to the output thread. You can use a linked list structure or queue and add it to the end of the list/queue. This will require a mutex to control write access to the queue because the writer will have to pop the head of the queue as it reads the data, but that way you are mostly reading and writing concurrently. There are also lockless queuing algorithms you might want to explore which can eliminate the need for a mutex. Unfortunately, while I know about them, I am not familiar with them, so some research is required on your part if you are interested in that sort of technique.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  7. #7
    Just Joined!
    Join Date
    May 2009
    Location
    Rolla, MO
    Posts
    5
    Can i have a global variable (an array of 80 bytes) and then fork a thread for a blocking serial read (into that array) and access that array in the parent thread to send data to the speaker? Will the blocking read affect the parent thread?

  8. #8
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,393
    A blocking read in a thread won't affect the parent or sibling threads. You can certainly create a buffer with a thread-local pointer to it that you read into. When the read is done, it sets a pointer shared by the reader and writer threads to the buffer. When the writer sees that the pointer is set, it writes it to the sound system. When done writing, it clears the shared pointer. The reader in the mean time has set its local pointer to another buffer that it continues to read into. When done, it either caches that buffer (if the writer hasn't cleared the shared pointer), or sets the shared pointer to either the oldest cached buffer, or if none then to the last read buffer. In order to reduce memory allocation/free overhead, and memory fragmentation, the usual situation in these cases is to use a ring buffer that is big enough to handle all pending output data, which would be some multiple of your 80 byte chunks. So, a 1K or 2K ring buffer should handle 12-25 chunks before overflowing.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  9. #9
    Just Joined!
    Join Date
    May 2009
    Location
    Rolla, MO
    Posts
    5
    I'll try that. Meanwhile, i came across this link: equalarea.com/paul/alsa-audio.html#interruptex
    This explains a call back driven mechanism for sound playback. Can I use this one along with a blocking read?

  10. #10
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,393
    Quote Originally Posted by Priyachu View Post
    I'll try that. Meanwhile, i came across this link: equalarea.com/paul/alsa-audio.html#interruptex
    This explains a call back driven mechanism for sound playback. Can I use this one along with a blocking read?
    This is fine for the output thread. It waits until the sound system is able to handle a certain amount of data and then passes up to that amount to it. This won't affect the reader. You might want to allocate a bigger ring buffer than the 1 or 2K I mentioned previously. The sound system obviously can handle a larger amount of data (4096 frames in this example - I don't know how many btyes are in a frame), so you would want your ring buffer to be some multiple of the maximum number of frames you will send to the sound system at any one time. You can continue to read 80 bytes at a time, and add them to the end of the ring buffer. The writer pulls up to 4096 frames off at a time (less if that much isn't available) and sends it to the sound system each time the sound system is ready for more data.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Page 1 of 2 1 2 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •