Agora-C_Sharp-SDK
Agora-C_Sharp-SDK copied to clipboard
Broadcasting custom audio to multiple channel at the same time
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?