Agora-C_Sharp-SDK icon indicating copy to clipboard operation
Agora-C_Sharp-SDK copied to clipboard

Broadcasting custom audio to multiple channel at the same time

Open nikskhubani opened this issue 1 year ago • 0 comments

We are preparing a c# application which basically is supposed to live streaming Custom audio to multiple Agora Channels at the same time. Here is the code we are trying to run:

Initialize Channel

/// <summary> 

/// Intialize agora and join channel. 

/// </summary> 

[Obsolete] 

public int InitializeAgora(string token, uint uid) 

{ 

     this.agoraEngine = RtcEngine.CreateAgoraRtcEngineEx(); 

  

     // Prepare engine context 

     RtcEngineContext rtc_engine_ctx = new RtcEngineContext( 

         this.agoraAppId, 

         0, 

         CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING, 

         AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT); 

  

     // RtcEngineContext rtc_engine_ctx = new RtcEngineContext(); 

     rtc_engine_ctx.appId = this.agoraAppId; 

  

     // Initialize engine 

     this.agoraEngine.Initialize(rtc_engine_ctx); 

  

     // Join channel 

     this.agoraEngine.EnableAudio(); 

     this.agoraEngine.EnableLocalAudio(false); 

     this.agoraEngine.SetAudioProfile(AUDIO_PROFILE_TYPE.AUDIO_PROFILE_MUSIC_STANDARD, AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_MEETING); 

     this.agoraEngine.SetEnableSpeakerphone(false); 

     this.agoraEngine.SetExternalAudioSource(true, 16000, 1); 

  

     // this.agoraEngine.SetExternalAudioSink(true, 16000, 1); 

     this.agoraEngine.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER); 

     this.agoraEngine.SetChannelProfile(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING); 

     int joinResult = this.agoraEngine.JoinChannel(token, this.channelName, string.Empty, uid); 

     return joinResult; 

} 

Publish Buffer

/// <summary> 

/// Send the audio buffer to agora. 

/// </summary> 

/// <param name="audioData">Buffer data.</param> 

public int SendAudioFrame(byte[] audioData) 

{ 

     int pushResult = 0; 

     try 

     { 

         long currentTimeMillis = (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 

  

         // Assuming you have the audio frame data in bytes, send it to Agora 

         AudioFrame audioFrame = new AudioFrame(); 

         audioFrame.samplesPerSec = this.agoraSamplerate; 

         audioFrame.channels = this.agoraChannels; 

         audioFrame.RawBuffer = audioData; 

         audioFrame.renderTimeMs = currentTimeMillis; 

         audioFrame.samplesPerChannel = audioData.Length / 2; 

         audioFrame.type = AUDIO_FRAME_TYPE.FRAME_TYPE_PCM16; 

  

         // audioFrame.sam = (BYTES_PER_SAMPLE)(audioData.Length / (this.agoraChannels * 2)); 

         pushResult = this.agoraEngine.PushAudioFrame( 

             audioFrame); 

     } 

     catch (Exception ex) 

     { 

         Console.WriteLine(ex.ToString()); 

     } 

  

     return pushResult; 

} 

 

Overall class looks something like this

// <copyright file="AgoraAudioBroadcaster.cs" company="Microsoft Corporation"> 

// Copyright (c) Microsoft Corporation. All rights reserved. 

// Licensed under the MIT license. 

// </copyright> 

  

namespace TeamsBot.Agora 

{ 

    using System; 

    using global::Agora.Rtc; 

    using Newtonsoft.Json.Linq; 

  

    /// <summary> 

    /// Broadcaster for agora. 

    /// </summary> 

    public class AgoraAudioBroadcaster 

    { 

        private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 

        private readonly int agoraSamplerate = 16000; 

        private readonly int agoraChannels = 1; 

        private string agoraAppId; 

        private string agoraAppCert; 

        private string channelName; 

        private IRtcEngine agoraEngine; 

  

        // private string token = "007eJxTYNBW29y2Pmjr9qu6dSJbv29K+2zz7VdfkdCt0+//dSgd/f1HgcHCONnS3NAwJcUwLcXEODHFwsLILNUsyTTFxDAxKdHUvIXnWkpDICODMAcXMyMDBIL4Egx5mSWZeQ6ZeSWpOTmZxclFmQUlxXrJ+bkMDABdpyol"; 

  

        /// <summary> 

        /// Constructor. 

        /// </summary> 

        /// <param name="agoraAppId"></param> 

        /// <param name="channelName"></param> 

        /// <param name="agoraAppCert"></param> 

        public AgoraAudioBroadcaster(string agoraAppId, string channelName, string agoraAppCert) 

        { 

            this.agoraAppId = agoraAppId; 

            this.channelName = channelName; 

            this.agoraAppCert = agoraAppCert; 

        } 

  

        /// <summary> 

        /// Intialize agora and join channel. 

        /// </summary> 

        [Obsolete] 

        public int InitializeAgora(string token, uint uid) 

        { 

            this.agoraEngine = RtcEngine.CreateAgoraRtcEngineEx(); 

  

            // Prepare engine context 

            RtcEngineContext rtc_engine_ctx = new RtcEngineContext( 

                this.agoraAppId, 

                0, 

                CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING, 

                AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT); 

  

            // RtcEngineContext rtc_engine_ctx = new RtcEngineContext(); 

            rtc_engine_ctx.appId = this.agoraAppId; 

  

            // Initialize engine 

            this.agoraEngine.Initialize(rtc_engine_ctx); 

  

            // Join channel 

            this.agoraEngine.EnableAudio(); 

            this.agoraEngine.EnableLocalAudio(false); 

            this.agoraEngine.SetAudioProfile(AUDIO_PROFILE_TYPE.AUDIO_PROFILE_MUSIC_STANDARD, AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_MEETING); 

            this.agoraEngine.SetEnableSpeakerphone(false); 

            this.agoraEngine.SetExternalAudioSource(true, 16000, 1); 

  

            // this.agoraEngine.SetExternalAudioSink(true, 16000, 1); 

            this.agoraEngine.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER); 

            this.agoraEngine.SetChannelProfile(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING); 

            int joinResult = this.agoraEngine.JoinChannel(token, this.channelName, string.Empty, uid); 

            return joinResult; 

        } 

  

        /// <summary> 

        /// Returns the app ID. 

        /// </summary> 

        /// <returns>returns the agora app ID.</returns> 

        public string GetAgoraAppId() 

        { 

            return this.agoraAppId; 

        } 

  

        /// <summary> 

        /// Send the audio buffer to agora. 

        /// </summary> 

        /// <param name="audioData">Buffer data.</param> 

        public int SendAudioFrame(byte[] audioData) 

        { 

            int pushResult = 0; 

            try 

            { 

                long currentTimeMillis = (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 

  

                // Assuming you have the audio frame data in bytes, send it to Agora 

                AudioFrame audioFrame = new AudioFrame(); 

                audioFrame.samplesPerSec = this.agoraSamplerate; 

                audioFrame.channels = this.agoraChannels; 

                audioFrame.RawBuffer = audioData; 

                audioFrame.renderTimeMs = currentTimeMillis; 

                audioFrame.samplesPerChannel = audioData.Length / 2; 

                audioFrame.type = AUDIO_FRAME_TYPE.FRAME_TYPE_PCM16; 

  

                // audioFrame.sam = (BYTES_PER_SAMPLE)(audioData.Length / (this.agoraChannels * 2)); 

                pushResult = this.agoraEngine.PushAudioFrame( 

                    audioFrame); 

            } 

            catch (Exception ex) 

            { 

                Console.WriteLine(ex.ToString()); 

            } 

  

            return pushResult; 

        } 

  

        /// <summary> 

        /// Dispose the agora engine and leave the channel. 

        /// </summary> 

        private void LeaveChannel() 

        { 

            this.agoraEngine.LeaveChannel(); 

            this.agoraEngine.Dispose(); 

            this.agoraEngine = null; 

        } 

    } 

} 

 

We create instance of the class using below code 

  private AgoraAudioBroadcaster ConfigureAgoraChannel(CallParticipantAddBody callParticipantAddBody) 

{ 

     var agoraAppId = this.configuration["AgoraAppId"]; 

     var agoraCert = this.configuration["AgoraCert"]; 

  

     AgoraAudioBroadcaster agoraAudioBroadcaster = new AgoraAudioBroadcaster(agoraAppId, callParticipantAddBody.UserPrincipalName, agoraCert); 

     var response = agoraAudioBroadcaster.InitializeAgora(callParticipantAddBody.AgoraSenderToken, (uint)callParticipantAddBody.SenderUDI); 

     return agoraAudioBroadcaster; 

} 

Problem

This code works just fine when we are trying to publish to the first channel. However, when we try to join the second channel, we get error code –17.

The app ID and certificate being used is the same, we do not have different app id for different channels.

Question

How can we publish the same audio stream to multiple agora channels at the same time?

nikskhubani avatar Sep 08 '23 10:09 nikskhubani