2015-09-04 5 views
8

मुझे एम्बेडेड लिनक्स सिस्टम का उपयोग करके एक रेडियो से माध्यमिक सिस्टम में ऑडियो भेजने की आवश्यकता है।लिनक्स कस्टम विलंब के साथ रैम बफर और प्लेबैक ऑडियो में ध्वनि रिकॉर्ड करने के लिए कैसे करें

द्वितीयक प्रणाली को एक संचार चैनल स्थापित करने की आवश्यकता है जिसमें कुछ सेकंड लगते हैं।

इसलिए यदि मैं ऑडियो की शुरुआत खोना नहीं चाहता, तो मुझे ध्वनि रिकॉर्ड करने और कस्टम विलंब (कुछ सेकंड अधिकतम) के साथ इसे वापस चलाने का एक तरीका चाहिए।

एक tmpfs फाइल सिस्टम में फ़ाइल में ऑडियो रिकॉर्ड करने के लिए arecord शुरू करना संभव है, और जब कोई संचार आ रहा है, तो aplay प्रारंभ करें। लेकिन इस मामले में शुरुआत अभी भी खो गई है क्योंकि रिकॉर्ड करने के लिए संकेत बहुत देर हो रहा है।

क्या लिनक्स पर कोई प्रोग्राम है जो रैम में एक अंगूठी बफर में निरंतर ध्वनि रिकॉर्ड कर रहा है और मांग पर कस्टम देरी के साथ प्लेबैक करने में सक्षम है?

यदि नहीं, तो एम्बेडेड सिस्टम पर ऐसे प्रोग्राम को कोड करने के लिए सबसे अच्छी लाइब्रेरी क्या है? अल्सा या कुछ और?

+0

लिनक्स पर, प्रत्येक ऑडियो लाइब्रेरी अंततः ALSA का उपयोग करके समाप्त होती है। हालांकि, यदि आप उपयोग करना आसान है तो आप किसी अन्य लाइब्रेरी का उपयोग कर सकते हैं। –

+0

क्या यह प्रश्न ऑफ-विषय है क्योंकि यह किसी टूल या लाइब्रेरी के लिए पूछता है? –

+0

आल्सा को LADSPA प्लगइन के लिए समर्थन है, एक निश्चित देरी की विशेषता होनी चाहिए। – Phillip

उत्तर

6

यहां एक साधारण सी प्रोग्राम है जो पाइप के अंदर और बाहर के बीच एक गोलाकार बफर बनाए रखेगा। in | buffer_program | out जैसे प्रयोग करें। छोड़े गए त्रुटि की जांच। मजबूती की गारंटी नहीं है। सामान्य विचार देता है।

टेस्ट स्क्रिप्ट (। लेकिन वास्तव में अपने परिपत्र जरूरतों में अपने पाइपिंग डेटा बफ़र कि उसका सुसंगत लेने बस किसी भी स्ट्रीम में हिस्सा या बस बफर डेटा से भी बड़ा बना होने के लिए के बाद से):

cat some.wav | ./circular_buffer 100000 | (sleep 1 && aplay) 

परिपत्र_बफर।सी:

/** 
* This program simply maintains a circular buffer of a given size indefinitely. 
*/ 
#include <stdio.h> 
#include <stddef.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdbool.h> /* C99 only */ 
#include <sys/select.h> 
#include <errno.h> 
#include <fcntl.h> 

int c_read(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in); 
int c_write(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in); 
bool empty_buf(unsigned int head, unsigned int tail); 
bool setblock(int fd, bool block); 
#define FD_SET_SET(set, fd, max) FD_SET(fd, &set); max = ((fd > max) ? fd : max); 
#define FD_SET_UNSET(set, fd, max) FD_CLR(fd, &set); max = ((fd == max) ? max - 1 : max); //not ideal. Do while ISFDSET... 

int main(int argc, char **argv) 
{ 
    char * buf; 
    unsigned int buf_size = 0; 
    unsigned int buf_head = 0; 
    unsigned int buf_tail = 0; 

    // Check args. 
    if(argc != 2) { 
    fprintf(stderr, "Usage: %s <buffer size in bytes>\n", __FILE__); 
    exit(EXIT_FAILURE); 
    } 
    sscanf(argv[1], "%d", &buf_size); 
    buf_size = (buf_size < 2) ? 2 : buf_size; 

    // Note the usable buffer space is buf_size-1. 
    fprintf(stderr, "Allocating %d\n", buf_size); 
    buf = (char*)malloc(buf_size); 

    bool done_reading = false; 
    int maxfd = 0; 
    fd_set r_set, w_set, r_tempset, w_tempset; 
    setblock(STDIN_FILENO, false); 
    setblock(STDOUT_FILENO, false); 
    FD_ZERO(&r_set); 
    FD_ZERO(&w_set); 
    FD_ZERO(&r_tempset); 
    FD_ZERO(&w_tempset); 
    FD_SET_SET(r_tempset, STDIN_FILENO, maxfd); 
    FD_SET_SET(w_tempset, STDOUT_FILENO, maxfd); 
    r_set = r_tempset; 
    while(true) { 
    select((maxfd + 1), &r_set, &w_set, NULL, NULL); 
    if(FD_ISSET(STDIN_FILENO, &r_set)) { 
     int c = c_read(STDIN_FILENO, buf, buf_size, &buf_head, &buf_tail); 
     if(c == -1) { // EOF, disable select on the input. 
     fprintf(stderr, "No more bytes to read\n"); 
     done_reading = true; 
     FD_ZERO(&r_set); 
     } 
    } 
    if(!done_reading) { 
     r_set = r_tempset; 
    } 
    if(FD_ISSET(STDOUT_FILENO, &w_set)) { 
     c_write(STDOUT_FILENO, buf, buf_size, &buf_head, &buf_tail); 
    } 
    if(!empty_buf(buf_head, buf_tail)) { // Enable select on write whenever there is bytes. 
     w_set = w_tempset; 
    } 
    else { 
     FD_ZERO(&w_set); 
     if(done_reading) { // Finish. 
     fprintf(stderr, "No more bytes to write\n"); 
     break; 
     } 
    } 
    } 
    fflush(stderr); 
    return 0; 
} 

bool empty_buf(unsigned int head, unsigned int tail) { 
    return head == tail; 
} 

/** 
* Keep reading until we can read no more. Keep on pushing the tail forward as we overflow. 
* Expects fd to be non blocking. 
* @returns number of byte read, 0 on non stopping error, or -1 on error or EOF. 
*/ 
int c_read(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in) { 
    fprintf(stderr, "In c_read()\n"); 
    unsigned int head = *head_in; 
    unsigned int tail = *tail_in; 
    bool more_bytes = true; 
    int n = 0; 
    int c = 0; 

    while(more_bytes) { 
    bool in_front = tail > head; 
    fprintf(stderr, "Read %d %d %d\n", size, head, tail); 

    n = read(fd, buf+head, size - head); 
    if(n == -1) { 
     more_bytes = false; 
     if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // Not EOF but the read would block. 
     c = 0; 
     } 
     else { 
     c = -1; 
     } 
    } 
    else if(n == 0) { // EOF. No more bytes possible. 
     more_bytes = false; 
     c = -1; 
    } 
    else if(n != (size - head)) { // if not full read adjust pointers and break. 
     more_bytes = false; 
     c += n; 
     head = (head+n)%size; 
     if(in_front && (head >= tail || head == 0)) { 
     tail = (head+1)%size; 
     } 
    } 
    else { 
     c = 0; 
     head = 0; 
     tail = (tail == 0) ? 1 : tail; 
    } 
    } 
    *head_in = head; 
    *tail_in = tail; 
    return c; 
} 

/** 
* Try flush the buffer to fd. fd should be non blocking. 
*/ 
int c_write(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in) { 
    fprintf(stderr, "In c_write()\n"); 
    unsigned int head = *head_in; 
    unsigned int tail = *tail_in; 
    int n = 0; 
    fprintf(stderr, "Write %d %d %d\n", size, head, tail); 

    if(tail < head) { 
    n = write(fd, buf+tail, head-tail); 
    tail += n; 
    } 
    else if(head < tail) { 
    n = write(fd, buf+tail, size-tail); 
    if(n == size-tail) { 
     n = write(fd, buf, head); 
     tail = n; 
    } 
    } 
    *head_in = head; 
    *tail_in = tail; 
    return n; 
} 

bool setblock(int fd, bool block) 
{ 
    int flags; 
    flags = fcntl(fd, F_GETFL); 
    if (block) 
     flags &= ~O_NONBLOCK; 
    else 
     flags |= O_NONBLOCK; 
    fcntl(fd, F_SETFL, flags); 
    return true; 
} 
1

आप सभी की जरूरत एक बफर ध्वनि उत्पादन रखने के लिए जब तक यह भस्म हो करने के लिए इस का एक प्रकार से काम करना चाहिए के लिए तैयार है लाना है:

प्रारंभ रिकॉर्डिंग:

mkfifo /tmp/f 
stdbuf -o256M arecord -i | cat > /tmp/f 

प्रारंभ खेल रहा है, जब तुम्हारा आउटपुट डिवाइस तैयार है:

aplay /tmp/f 

आउटपुट बफर आकार को अपनी आवश्यकताओं के अनुसार ट्विक करें।

संपादित करें (दिए गए खेल कभी भी शुरू कर सकते हैं कि):

आप लगातार रिकॉर्ड करने के लिए की जरूरत है और खेल रहे किसी भी समय आप split आदेश का उपयोग कर छोटी फ़ाइलों में उत्पादन विभाजित कर सकते शुरू करने और पुराने फाइलों को डिलीट एक सहायक प्रक्रिया।

कुछ की तरह:

# Garbage collector 
(while sleep 1 ; do rm $(ls *.blb 2>/dev/null | sort | head -n-3) > /dev/null 2>&1 ; done) & 
# Actual recording 
arecord -i | split -a 10 -u -b 24576 --additional-suffix '.blb' 

और खेलने के लिए:

{ while true ; do for f in $(find . -name '*.blb' -size 24576c | sort) ; do cat $f ; rm $f ; done ; done } | aplay 

यह समाधान काफी गंदा है, लेकिन हो सकता है काम (अधिमानतः tmpfs पर के रूप में आप पहले से ही उल्लेख किया है) ...

+0

मैं सर्कुलर बफर के साथ हर समय रिकॉर्ड करना चाहता हूं (8000 हर्ट्ज 8 बिट ऑडियो के 60 के लिए केवल 240 के लिए हो सकता है) और फिर जब इसे खेलना चाहिए, तो यह बफर में सही स्थिति से खेलने के लिए डीडी का उपयोग करेगा। बफर भरने पर आपके मामले में stdbuf ब्लॉक होगा। –

+0

फिर मैंने आपके प्रश्न को गलत समझा। मैं एक और विचार के साथ संपादित करूंगा (जो _perfect solution_ नहीं है, लेकिन एक _working समाधान _ हो सकता है) ... – vlp

संबंधित मुद्दे