diff --git a/firebaseai/src/LiveSession.cs b/firebaseai/src/LiveSession.cs index 52030a7d..38719b4d 100644 --- a/firebaseai/src/LiveSession.cs +++ b/firebaseai/src/LiveSession.cs @@ -141,29 +141,71 @@ public async Task SendAsync( } /// - /// Send realtime input to the server. + /// Sends realtime input (media chunks) to the server. /// - /// A list of media chunks to send. - /// A token to cancel the send operation. - public async Task SendMediaChunksAsync( + /// The list of media chunks to send. + [Obsolete("Use SendAudio, SendVideo, or SendText instead")] + public Task SendMediaChunksAsync( List mediaChunks, CancellationToken cancellationToken = default) { - if (mediaChunks == null) return; + if (mediaChunks == null) return Task.CompletedTask; + + return SendRealtimeInputAsync(cancellationToken: cancellationToken); + } + + /// + /// Sends audio data to the server. + /// + /// The audio data to send. + public Task SendAudioAsync(ModelContent.InlineDataPart audio, CancellationToken cancellationToken = default) { + return SendRealtimeInputAsync(audio: audio, cancellationToken: cancellationToken); + } + /// + /// Sends video data to the server. + /// + /// The video data to send. + public Task SendVideoAsync(ModelContent.InlineDataPart video, CancellationToken cancellationToken = default) { + return SendRealtimeInputAsync(video: video, cancellationToken: cancellationToken); + } + + /// + /// Sends text data to the server. + /// + /// The text data to send. + public Task SendTextAsync(string text, CancellationToken cancellationToken = default) { + return SendRealtimeInputAsync(text: text, cancellationToken: cancellationToken); + } + + private Task SendRealtimeInputAsync( + ModelContent.InlineDataPart? audio = null, + ModelContent.InlineDataPart? video = null, + string text = null, + CancellationToken cancellationToken = default) { // Prepare the message payload. Dictionary jsonDict = new() { { - "realtimeInput", new Dictionary() { - { - // InlineDataPart inherits from Part, so this conversion should be safe. - "mediaChunks", mediaChunks.Select(mc => (mc as ModelContent.Part).ToJson()["inlineData"]).ToList() - } - } + "realtimeInput", new Dictionary() } }; + + var realtimeInputDict = (Dictionary)jsonDict["realtimeInput"]; + + if (audio.HasValue) { + realtimeInputDict["audio"] = (audio.Value as ModelContent.Part).ToJson()["inlineData"]; + } + + if (video.HasValue) { + realtimeInputDict["video"] = (video.Value as ModelContent.Part).ToJson()["inlineData"]; + } + + if (!string.IsNullOrEmpty(text)) { + realtimeInputDict["text"] = text; + } + var byteArray = Encoding.UTF8.GetBytes(Json.Serialize(jsonDict)); - await InternalSendBytesAsync(new ArraySegment(byteArray), cancellationToken); + return InternalSendBytesAsync(new ArraySegment(byteArray), cancellationToken); } private static byte[] ConvertTo16BitPCM(float[] samples) { @@ -189,7 +231,7 @@ private static byte[] ConvertTo16BitPCM(float[] samples) { /// A token to cancel the send operation. public Task SendAudioAsync(float[] audioData, CancellationToken cancellationToken = default) { ModelContent.InlineDataPart inlineDataPart = new("audio/pcm", ConvertTo16BitPCM(audioData)); - return SendMediaChunksAsync(new List(new []{inlineDataPart}), cancellationToken); + return SendAudioAsync(inlineDataPart, cancellationToken); } ///