diff --git a/src/python/rpitx/_hidden.py b/src/python/rpitx/_hidden.py index a9881cb..ccb82db 100644 --- a/src/python/rpitx/_hidden.py +++ b/src/python/rpitx/_hidden.py @@ -1,42 +1,57 @@ """Hides imports and other irrelevant things so that ipython works nicely.""" -from pydub import AudioSegment import _rpitx -import io -import array +import ffmpegwrapper +import libavwrapper import logging -import wave +import os +import subprocess +import threading -def broadcast_fm(file_, frequency): - """Play a music file over FM.""" +def broadcast_fm(media_file_name, frequency): + """Play a media file's audio over FM.""" logging.basicConfig() logger = logging.getLogger('rpitx') - def _reencode(file_name): - """Returns an AudioSegment file reencoded to the proper WAV format.""" - original = AudioSegment.from_file(file_name) - if original.channels > 2: - raise ValueError('Too many channels in sound file') - if original.channels == 2: - # TODO: Support stereo. For now, just overlay into mono. - logger.info('Reducing stereo channels to mono') - left, right = original.split_to_mono() - original = left.overlay(right) + if subprocess.call(('which', 'ffmpeg')) == 1: + Input = ffmpegwrapper.Input + Output = ffmpegwrapper.Output + VideoCodec = ffmpegwrapper.VideoCodec + AudioCoded = ffmpegwrapper.AudioCodec + Stream = ffmpegwrapper.FFmpeg + command = 'ffmpeg' + elif subprocess.call(('which', 'avconv')) == 1: + Input = libavwrapper.Input + Output = libavwrapper.Output + VideoCodec = libavwrapper.VideoCodec + AudioCoded = libavwrapper.AudioCodec + Stream = libavwrapper.AVConv + command = 'avconv' + else: + raise NotImplementedError( + 'Broadcasting audio requires either avconv or ffmpeg to be installed' + ) - return original + logger.debug('Using {}'.format(command)) - raw_audio_data = _reencode(file_) + pipe_name = '/tmp/rpitx-fifo.wav' + if not os.path.exists(pipe_name): + os.mkfifo(pipe_name) - wav_data = io.BytesIO() - wav_writer = wave.open(wav_data, 'w') - wav_writer.setnchannels(1) - wav_writer.setsampwidth(2) - wav_writer.setframerate(48000) - wav_writer.writeframes(raw_audio_data.raw_data) - wav_writer.close() + def convert(): + """Runs the conversion command and writes to a FIFO.""" + input_media = Input(media_file_name) + codec = AudioCodec('pcm_s16le').frequence(48000).channels(1) + output_audio = Output(pipe_name, pipe_out) + stream = Stream(command, input_media, output_audio) + stream.add_option('-y', '') # Force overwriting existing file + logger.debug('Extracting and converting audio') + stream.run() - raw_array = array.array('b', wav_data.getvalue()) - array_address, length = raw_array.buffer_info() - _rpitx.broadcast_fm(array_address, length, frequency) + thread = threading.Thread(target=convert) + thread.start() + logger.debug('Calling broadcast_fm') + _rpitx.broadcast_fm(pipe_name, frequency) + thread.join()