diff --git a/.gitignore b/.gitignore index af3ca5e..888e967 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,11 @@ docs/_build/ .vscode/ # Pyenv -.python-version \ No newline at end of file +.python-version + +# Environment variables +.env + +*.wav + +demos/audio/uv.lock \ No newline at end of file diff --git a/demos/audio/README.md b/demos/audio/README.md new file mode 100644 index 0000000..39e64cd --- /dev/null +++ b/demos/audio/README.md @@ -0,0 +1,10 @@ +# wave_audio_receive.py + +six 15 second tests: +```bash +for i in {1..6};do timeout 15s uv run python wav_audio_receive.py; done +``` +or +```bash +for i in {1..6};do timeout 15s python3 -m wav_audio_receive; done +``` \ No newline at end of file diff --git a/demos/audio/pyproject.toml b/demos/audio/pyproject.toml new file mode 100644 index 0000000..45e6006 --- /dev/null +++ b/demos/audio/pyproject.toml @@ -0,0 +1,13 @@ +[project] +name = "wav-audio-receive" +version = "0.1.0" +description = "Demo that joins a Pipecat Cloud call and records audio to WAV" +requires-python = ">=3.10" +dependencies = [ + "daily-python", + "python-dotenv>=1.2.1", + "requests", +] + +[project.scripts] +wav-audio-receive = "wav_audio_receive:main" diff --git a/demos/audio/wav_audio_receive.py b/demos/audio/wav_audio_receive.py index bdbf1c3..d05e391 100644 --- a/demos/audio/wav_audio_receive.py +++ b/demos/audio/wav_audio_receive.py @@ -1,26 +1,30 @@ # -# This demo will join a Daily meeting and record the meeting audio into a -# WAV. +# This demo will start a Pipecat Cloud app, join the call, and record the +# meeting audio into a WAV. # -# Usage: python3 wav_audio_receive.py -m MEETING_URL -o FILE.wav # import argparse +import os +import requests import threading import wave +from dotenv import load_dotenv from daily import * SAMPLE_RATE = 16000 NUM_CHANNELS = 1 +load_dotenv(override=True) + class ReceiveWavApp: def __init__(self, input_file_name, sample_rate, num_channels): self.__sample_rate = sample_rate self.__speaker_device = Daily.create_speaker_device( - "my-speaker", sample_rate=sample_rate, channels=num_channels + "my-speaker", sample_rate=sample_rate, channels=num_channels, non_blocking=False ) Daily.select_speaker_device("my-speaker") @@ -47,8 +51,8 @@ def on_joined(self, data, error): self.__app_error = error self.__start_event.set() - def run(self, meeting_url): - self.__client.join(meeting_url, completion=self.on_joined) + def run(self, meeting_url, meeting_token=None): + self.__client.join(meeting_url, meeting_token, completion=self.on_joined) self.__thread.join() def leave(self): @@ -73,22 +77,53 @@ def receive_audio(self): self.__wave.close() +def start_pipecat_app(api_key): + response = requests.post( + "https://api.pipecat.daily.co/v1/public/daily-python-virtual-speaker-test/start", + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + json={ + "createDailyRoom": True, + "transport": "daily", + "dailyMeetingTokenProperties": { + "is_owner": True + # "enable_auto_recording": True + # "start_cloud_recording": True + }, + "dailyRoomProperties": {"enable_recording": "cloud"}, + }, + ) + response.raise_for_status() + data = response.json() + print(f"_____wav_audio_receive.py * data: {data}") + return data["dailyRoom"], data.get("dailyToken") + + def main(): parser = argparse.ArgumentParser() - parser.add_argument("-m", "--meeting", required=True, help="Meeting URL") + parser.add_argument("-k", "--api-key", required=False, help="Pipecat API key") parser.add_argument( "-c", "--channels", type=int, default=NUM_CHANNELS, help="Number of channels" ) parser.add_argument("-r", "--rate", type=int, default=SAMPLE_RATE, help="Sample rate") - parser.add_argument("-o", "--output", required=True, help="WAV output file") + # parser.add_argument("-o", "--output", help="WAV output file") args = parser.parse_args() Daily.init() - app = ReceiveWavApp(args.output, args.rate, args.channels) + api_key = os.getenv("PIPECAT_API_KEY", args.api_key) + room_url, token = start_pipecat_app(api_key) + print(f"Started Pipecat app: {room_url}") + + room_name = room_url.rstrip("/").split("/")[-1] + output = f"{room_name}.wav" + app = ReceiveWavApp(output, args.rate, args.channels) try: - app.run(args.meeting) + # print(f"_____wav_audio_receive.py * token: {token}") + app.run(room_url, token) except KeyboardInterrupt: print("Ctrl-C detected. Exiting!") finally: