LogStreamer est un logiciel permettant la diffusion sonore d'un fichier via un serveur Icecast
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logstreamer.py 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/usr/bin/env python3
  2. import os
  3. import wave
  4. import math
  5. import shout
  6. import struct
  7. import random
  8. import argparse
  9. import subprocess
  10. def sine_wave(frequency=444, framerate=44100, amplitude=0.5, duration=1):
  11. """
  12. frequency: La fréquence à échantillonner
  13. framerate: Le taux d'échantillonnage
  14. amplitude: Le volume sonore (de 0 à 1)
  15. duration: La durée de l'échantillon en seconde
  16. """
  17. amplitude = amplitude * 32767
  18. if amplitude > 32767:
  19. amplitude = 32767
  20. elif amplitude < 0:
  21. amplitude = 0
  22. data = []
  23. for i in range(int(duration * framerate)):
  24. value = int(amplitude*math.cos(2*frequency*math.pi*float(i)/float(framerate)))
  25. data.append(value)
  26. return struct.pack('<{}h'.format(len(data)), *data)
  27. def notes_table(oord):
  28. freq = math.fabs(math.floor(math.log(oord)*int(args.adjust[0])-int(args.adjust[1])))
  29. duration = args.duration
  30. return (freq, duration)
  31. def convert2ogg(wav_file, ogg_file):
  32. result = subprocess.call(['oggenc', wav_file, '-o', '{}'.format(ogg_file)])
  33. return result
  34. def push_ogg(ogg_file):
  35. icecast = shout.Shout()
  36. icecast.host = args.host
  37. icecast.port = args.port
  38. icecast.user = args.user
  39. icecast.password = args.password
  40. icecast.mount = args.mount
  41. icecast.protocol = args.protocol
  42. icecast.format = 'ogg'
  43. print("Connexion au serveur {}://{}:{} {}".format(args.protocol, args.host, args.port, args.mount))
  44. print("Taille du tampon: {} octets".format(args.ice_buffer))
  45. icecast.open()
  46. with open(ogg_file, 'rb') as ogg:
  47. total = 0
  48. if args.debug:
  49. print("- Lecture de {} octets".format(args.ice_buffer))
  50. new_buff = ogg.read(args.ice_buffer)
  51. while True:
  52. cur_buff = new_buff
  53. if args.debug:
  54. print("- Lecture des {} octets suivants".format(args.ice_buffer))
  55. new_buff = ogg.read(args.ice_buffer)
  56. total += len(cur_buff)
  57. if len(cur_buff) == 0:
  58. print("- Tampon vide => Fin du fichier")
  59. print("- Nombre d'octets envoyés: {}".format(total))
  60. break
  61. if args.debug:
  62. print("- Envoi de {} octets".format(args.ice_buffer))
  63. icecast.send(cur_buff)
  64. icecast.sync()
  65. def main():
  66. wav_output = "{}.wav".format(os.path.basename(args.log).split('.')[0])
  67. wav_output = os.path.join(args.workdir, wav_output)
  68. ogg_output = "{}.ogg".format(os.path.basename(args.log).split('.')[0])
  69. ogg_output = os.path.join(args.workdir, ogg_output)
  70. with wave.open(wav_output, 'wb') as wave_file:
  71. nchannels = 1
  72. sampwidth = 2
  73. framerate = args.framerate
  74. wave_file.setnchannels(nchannels)
  75. wave_file.setsampwidth(sampwidth)
  76. wave_file.setframerate(framerate)
  77. try:
  78. with open(args.log, 'r') as log:
  79. for letter in log.read():
  80. oord = ord(letter)
  81. freq, duration = notes_table(oord)
  82. if oord not in args.exclude:
  83. if args.debug:
  84. print("Caractère: {} | Ord: {} | Fréquence: {} | Durée: {}".format(letter, oord, freq, duration))
  85. wave_file.writeframes(sine_wave(frequency=freq, duration=duration))
  86. result = convert2ogg(wav_output, ogg_output)
  87. if result == 0:
  88. push_ogg(ogg_output)
  89. else:
  90. raise Exception("Erreur lors de la conversion en OGG: {}".format(result))
  91. except Exception as e:
  92. print('\033[91m{}\033[0m'.format(e))
  93. if __name__ == '__main__':
  94. parser = argparse.ArgumentParser()
  95. parser.add_argument('--log', help='Le fichier de log à traiter (requis)', type=str, required=True)
  96. parser.add_argument('--host', help="Server Icecast2 (requis)", type=str, required=True)
  97. parser.add_argument('--port', help="Port TCP sur lequel contacter le serveur Icecast2 (requis)", type=int, required=True)
  98. parser.add_argument('--user', help="Nom d'utilisateur (requis)", type=str, required=True)
  99. parser.add_argument('--password', help="Mot de passe (requis)", type=str, required=True)
  100. parser.add_argument('--mount', help="Point de montage Icecast2 (requis)", type=str, required=True)
  101. parser.add_argument('--workdir', help='Le répertoire de travail (défaut: /tmp)', type=str, default='/tmp')
  102. parser.add_argument('--duration', help="La durée d'une note (défaut: 0.008)", type=float, default=0.08)
  103. parser.add_argument('--amplitude', help="Le niveau sonore (défaut: 0.5)", type=float, default=0.5)
  104. parser.add_argument('--framerate', help="Le taux d'échantillonage (défaut: 44100)", type=int, default=44100)
  105. parser.add_argument('--adjust', help="Facteurs d'ajustement (défaut: 5000 20000)", nargs=2, default=[5000, 20000])
  106. parser.add_argument('--exclude', help="Liste des caractères non traités (défaut: [])", nargs="*", default=[])
  107. parser.add_argument('--protocol', help="Protocole à utiliser (défaut: http)", type=str, default='http')
  108. parser.add_argument('--ice_buffer', help="Taille du tampon Icecast (défaut: 32768)", type=int, default=32768)
  109. parser.add_argument('--debug', help="Affiche l'activité (défaut: False)", type=bool, default=False)
  110. args = parser.parse_args()
  111. main()