Add experimental HTTP streaming using ffmpeg/ffserver
This commit is contained in:
parent
ce03cf4447
commit
88b98baffd
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
||||||
|
# See LICENSE.txt for copyright info
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from frn.protocol.client import FRNClient, FRNClientFactory
|
||||||
|
from frn.user import FRNUser
|
||||||
|
from twisted.internet import reactor, task
|
||||||
|
from twisted.internet.defer import DeferredList
|
||||||
|
from twisted.python import log
|
||||||
|
import os, string
|
||||||
|
from Queue import Queue
|
||||||
|
from twisted.internet.task import LoopingCall
|
||||||
|
import fcntl
|
||||||
|
|
||||||
|
STREAM_CMD="""tools/gsmdecode|ffmpeg -ar 8000 -ac 1 -f s16le -i /dev/stdin http://127.0.0.1:8090/feed.ffm"""
|
||||||
|
|
||||||
|
silence_frame = open("sounds/silence-gsm.gsm", "rb").read()
|
||||||
|
|
||||||
|
class FRNStream(FRNClient):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._frames = Queue()
|
||||||
|
self._stream = subprocess.Popen(STREAM_CMD, shell=True,
|
||||||
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
self._streamtimer = LoopingCall.withCount(self.sendStreamFrame)
|
||||||
|
self._streamtimer.start(0.20)
|
||||||
|
|
||||||
|
def getClientName(self, client_id):
|
||||||
|
if self.clientsById.has_key(client_id):
|
||||||
|
return self.clientsById[client_id]['on']
|
||||||
|
else:
|
||||||
|
return client_id
|
||||||
|
|
||||||
|
def audioFrameReceived(self, from_id, frames):
|
||||||
|
self._frames.put_nowait(frames)
|
||||||
|
self.pong()
|
||||||
|
|
||||||
|
def sendStreamFrame(self, count):
|
||||||
|
for i in range(count):
|
||||||
|
if self._frames.empty():
|
||||||
|
frames = silence_frame
|
||||||
|
else:
|
||||||
|
frames = self._frames.get_nowait()
|
||||||
|
self._stream.stdin.write(frames)
|
||||||
|
self._stream.stdin.flush()
|
||||||
|
self._stream.stdout.flush()
|
||||||
|
self._stream.stderr.flush()
|
||||||
|
|
||||||
|
def loginResponse(self, info):
|
||||||
|
log.msg("Login: %s" % info['al'])
|
||||||
|
|
||||||
|
def clientsListUpdated(self, clients):
|
||||||
|
self.clients = clients
|
||||||
|
self.clientsById = dict([(i['id'], i) for i in clients])
|
||||||
|
|
||||||
|
|
||||||
|
class FRNStreamFactory(FRNClientFactory):
|
||||||
|
protocol = FRNStream
|
||||||
|
reactor = reactor
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
from os.path import dirname, join as pjoin
|
||||||
|
from ConfigParser import ConfigParser
|
||||||
|
|
||||||
|
log.startLogging(sys.stderr)
|
||||||
|
|
||||||
|
basedir = dirname(__file__)
|
||||||
|
|
||||||
|
acfg = ConfigParser()
|
||||||
|
acfg.read(['/etc/grn/accounts.conf',
|
||||||
|
pjoin(basedir,'accounts.conf'), 'accounts.conf'])
|
||||||
|
|
||||||
|
scfg = ConfigParser()
|
||||||
|
scfg.read(['/etc/grn/servers.conf',
|
||||||
|
pjoin(basedir,'servers.conf'), 'servers.conf'])
|
||||||
|
|
||||||
|
argc = len(sys.argv)
|
||||||
|
if argc >= 3:
|
||||||
|
server_name, network_name = sys.argv[2].split(':',1)
|
||||||
|
account_cfg = acfg.items(sys.argv[1])+[('network', network_name)]
|
||||||
|
server_cfg = scfg.items(server_name)
|
||||||
|
server = scfg.get(server_name, 'server')
|
||||||
|
port = scfg.getint(server_name, 'port')
|
||||||
|
|
||||||
|
d = dict(account_cfg)
|
||||||
|
user = FRNUser(
|
||||||
|
EA=d['email'],
|
||||||
|
PW=d['password'], ON=d['operator'],
|
||||||
|
BC=d['transmission'], DS=d['description'],
|
||||||
|
NN=d['country'], CT=d['city'], NT=d['network'])
|
||||||
|
reactor.connectTCP(server, port, FRNStreamFactory(user))
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
|
# vim: set et ai sw=4 ts=4 sts=4:
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
*%
|
||||||
|
gsmdecode
|
|
@ -0,0 +1,15 @@
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS=-Wall -O2 -I/usr/include/gsm
|
||||||
|
LDFLAGS=-lgsm
|
||||||
|
|
||||||
|
all: gsmdecode
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *~ *% *.o
|
||||||
|
$(RM) gsmdecode
|
||||||
|
|
||||||
|
gsmdecode: gsmdecode.c
|
||||||
|
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -6,12 +7,9 @@
|
||||||
int main() {
|
int main() {
|
||||||
gsm handle = gsm_create();
|
gsm handle = gsm_create();
|
||||||
int one = 1;
|
int one = 1;
|
||||||
int zero = 0;
|
|
||||||
gsm_option(handle, GSM_OPT_WAV49, &one);
|
gsm_option(handle, GSM_OPT_WAV49, &one);
|
||||||
unsigned char src610[65];
|
unsigned char src610[65];
|
||||||
gsm_frame src;
|
|
||||||
gsm_signal dst[160];
|
gsm_signal dst[160];
|
||||||
unsigned char outbuff[160];
|
|
||||||
while (!feof(stdin)) {
|
while (!feof(stdin)) {
|
||||||
int rv = fread(src610, 65, 1, stdin);
|
int rv = fread(src610, 65, 1, stdin);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
|
@ -23,7 +21,6 @@ int main() {
|
||||||
}
|
}
|
||||||
int frameIndex = 0;
|
int frameIndex = 0;
|
||||||
for (frameIndex = 0; frameIndex <= 1; frameIndex++) {
|
for (frameIndex = 0; frameIndex <= 1; frameIndex++) {
|
||||||
int iFrameIndex = !frameIndex;
|
|
||||||
gsm_decode(handle, src610 + 33 * frameIndex, dst);
|
gsm_decode(handle, src610 + 33 * frameIndex, dst);
|
||||||
rv = fwrite(dst, sizeof dst, 1, stdout);
|
rv = fwrite(dst, sizeof dst, 1, stdout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
|
@ -33,4 +30,6 @@ int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gsm_destroy(handle);
|
gsm_destroy(handle);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
||||||
|
|
Loading…
Reference in New Issue